home *** CD-ROM | disk | FTP | other *** search
- PAGE 55,130
- ; SPCTAB
- ;
-
- bufspc equ 0400h
- stkspc equ 0100h
- midbuf equ 0200h
-
- codeseg segment
- assume cs:codeseg, ds:codeseg
-
-
- org 100h
-
- spctab proc far
-
- start: jmp init
-
- ; messages -
- errmsg1 db 0Dh, 0Ah, 'Read Error', 0Dh, 0Ah, '$'
- errmsg2 db 0Dh, 0Ah, 'Could not get enough memory.', 0Dh, 0Ah, '$'
- help_msg db 0Dh, 0Ah, 'SPCTAB is a filter that converts spaces'
- db ' in standard input to TABs in standard', 0Dh, 0Ah
- db 'output where possible. It also trims a line, that'
- db ' is, it deletes all trailing', 0Dh, 0Ah
- db 'spaces in a line.', 0Dh, 0Ah, 0Dh, 0Ah
- db 'Usage: SPCTAB [<fname] [>fname]', 0Dh, 0Ah, '$'
- errmsg3 db 0Dh, 0Ah, 'Write Error', 0Dh, 0Ah, '$'
-
- ; variables -
- count dw 0
-
- ; Note - space for the 1024 byte buffer and the 256 byte stack is allocated
- ; here, rather than being stored in the task image on disk.
- ;
-
- init: mov bx,offset buffer + bufspc + stkspc ; req. mem.
- add bx,010h
- mov cl,4
- shr bx,cl ; get it in paragraphs
- mov ah,04Ah ; set it - cf=1 if error
- int 021h
- mov dx,offset errmsg2
- jc err_exit ; exit with error message
- mov ax,0
- mov di,offset buffer ; else initialize buffer
- mov cx,bufspc + stkspc ; and stack space to 0
- shr cx,1 ; (div by 2 for words)
- cld
- rep stosw
- mov sp,offset buffer + bufspc + stkspc ; init sp
-
- mov si,80h ; get cmd line char count
- cmp byte ptr [si],0 ; into cx and incr by 1
- je Main
- mov cl,[si]
- inc cx
-
- skpspc: inc si ; skip any blanks
- cmp byte ptr [si],20h
- loopz skpspc
-
- jcxz Main ; skip if cmd line is all
- cmp byte ptr [si],3Fh ; spaces. Check for '?'
- jne Main ; ignore other chars
- mov dx,offset help_msg ; if '?' found, exit with
- jmp short err_exit ; 'help' message
-
- Main: call get_line ; get line from std input
- jc err_exit ; cf=1 is error
- or ax,ax
- jz norm_exit ; 0 char count is end
- call fix_line ; convert spcs to tabs
- call put_line ; write line to std output
- jc err_exit ; if cf=1, exit with err msg
- jmp short Main ; else continue.
-
- ; Note - here err_exit outputs the messages to std error rather than std
- ; out, so even if I/O is redirected from the cmd line, the message
- ; will be output to the console rather than the output file.
-
- err_exit: mov di,dx ; point di to error message
- mov cx,0FFh ; set cx to 255 ( countdown limit )
- mov al,024h ; "$"
- cld
- repnz scasb ; incr di to message terminator
- dec di ; decr to last char of message
- mov cx,di ; arithmetic to get char count in cx
- sub cx,dx
- mov bx,2 ; handle for std error
- mov ah,040h ; output message
- int 021h
- mov al,1 ; exit status = 1
- norm_exit: mov ah,04Ch
- int 021h
-
- spctab endp
-
-
- ; SUBROUTINE
- ; gets a line from std input
-
- get_line proc near
- mov si,offset buffer
-
- get_1: mov dx,si
- mov bx,0 ; handle for std input
- mov cx,1
- mov ah,03Fh ; read cx chars
- int 021h
- jc get_err ; cf=1 if input error
- cmp byte ptr [si],0Ah ; eoln found
- je get_ok
- or ax,ax ; ax=0 if kybd input eof
- jz get_ok
- xor ax,ax ; (make ax=0 on eof)
- cmp byte ptr [si],1Ah ; eof found (disk file)
- je get_ok
- inc si
- jmp short get_1
-
- get_ok: clc
- ret
-
- get_err: mov dx,offset errmsg1
- stc
- ret
-
- get_line endp
-
-
-
- ; SUBROUTINE
- ; This is where the transformation takes place.
- ; Basically, you're on your own to understand this.
- ;
-
- fix_line proc near
- mov count,0
- mov si,offset buffer
- mov di,offset buffer + midbuf
-
- xor bx,bx
-
- fix_loop_1: lodsb ; get a char (adv si)
-
- bigloop: cmp al,020h ; BL ?
- je fix_2 ; yes, next procedure.
- cmp al,0Dh ; CR ?
- jne fix_1a
- sub di,bx ; skip this if CR
-
- fix_1a: stosb ; not BL, not CR, so store it (adv di)
- cmp al,9 ; HT ?
- jne fix_1b ; if not, skip this
- add count,8 ; yes, add 8 to count
- and count,0FFF8h ; discard mod 8 remainder
- inc bx ; incr bx value
- jmp short fix_loop_1 ; continue
-
- fix_1b: inc count ; non-space char, incr count
- cmp al,0Ah ; check for NL
- je fix_done ; (exit this scene - line done.)
- xor bx,bx ; not NL, null bx value
- jmp short fix_loop_1 ; continue
- ; ----------
-
- fix_2: push bx ; point bx to first BL input
- mov bx,si
- dec bx
-
- fix_3: lodsb ; while char is BL, cont to get
- cmp al,020h
- je fix_3
-
- mov dx,si ; point dx to last BL input
- dec dx
- sub dx,bx ; subtract bx to get # of BL's
- mov ax,count ; put count in ax and bx
- mov bx,ax
- add ax,8 ; advance ax to next TS
- and ax,0FFF8h
- sub ax,bx ; subtract pos of 1st BL in series
- pop bx ; restore old bx value
- xor cx,cx ; null cx
- cmp dx,ax
- jb fix_4 ; dx hasn't reached next TS yet
- add count,ax ; dx reached next TS, add ax to count
- mov bx,1 ; set bx value to 1
- sub dx,ax ; move pointer back ax BL's
- mov al,9 ; output a Tab char.
- stosb ; (di is keeping track here)
- mov cx,dx ; put dx value in cx
- shr cx,1 ; and divide by 8 (# of TS's)
- shr cx,1
- shr cx,1
-
- fix_4: cmp byte ptr [si-1],9 ; was last char output a tab?
- jne fix_5 ; if not, skip this next
- inc cx ; else add 1 TS
- inc si ; incr char pointer
- and dx,0FFF8h ; discard dx mod 8 remainder
- jmp short fix_4 ; continue while char = tab.
-
- fix_5: or cx,cx ; if cx=0 skip this next
- jz fix_6
- add bx,cx ; add cx to bx tab count
- mov ax,cx ; put cx into ax
- shl ax,1 ; multiply by 8
- shl ax,1
- shl ax,1
- add count,ax ; add ax to count
- mov al,9 ; put tab char in al
- rep stosb ; output cx tabs (adv di)
-
- fix_6: mov cx,dx ; put output pointer in cx
- and cx,7 ; cx mod 8
- or cx,cx ; if it's 0, skip next
- jz fix_7
- add bx,cx ; else add cx to bx counter
- add count,cx ; add cx to count (?)
- mov al,020h ; put BL in al
- rep stosb ; output cx BL's (adv di)
-
- fix_7: mov al,[si-1] ; put that last char back in al
- jmp bigloop ; and do it again.
-
- fix_done: mov cx,di ; put di pointer in cx
- sub cx,offset buffer + midbuf ; sub start of buffer
- ret
-
- fix_line endp
-
-
-
- ; SUBROUTINE
- ; sends line to std output
-
- put_line proc near
- jcxz put_ok
- push cx ; cx should have char count
- mov dx,offset buffer + midbuf
- mov bx,1 ; handle for std output
- mov ah,040h ; output cx chars.
- int 021h
- pop cx
- jc put_err ; cf=1 if error.
- sub cx,ax ; ax = cx if ok.
- jnz put_err
-
- put_ok: clc
- ret
-
- put_err: mov dx,offset errmsg3
- stc
- ret
-
- put_line endp
-
-
- buffer db 0 ; buffer area: 1024 bytes allocated
- ; at pgm start (followed by 256 stack).
- codeseg ends
- end start
-